﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using com.IronOne.BoardPACWinAppBO.Auth;
using com.IronOne.BoardPACWinAppBO.General;
using com.IronOne.BoardPACWinAppBO.Settings;
using com.IronOne.BoardPACWinAppDAO.Auth;
using com.IronOne.BoardPACWinAppDAO.DbOperations;
using com.IronOne.BoardPACWinAppService.Xml;
using com.IronOne.BoardPACWinAppUtil.Enums;
using com.IronOne.BoardPACWinAppUtil.Security;
using com.IronOne.BoardPACWinAppUtil.Util;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;

namespace com.IronOne.BoardPACWinAppService.Auth
{
    public class AuthService : IAuthService
    {
        private readonly IAuthDAO _authDAO;
        private readonly IDbOperations _dbOperation;

        public AuthService()
        {
            _dbOperation = new DbOperations();
            _authDAO = new AuthDAO();
        }

        public async Task<ResponseDataModel> LogOn(LogOnModel logOnModel)
        {
            try
            {
                var postData = new Dictionary<string, string>
                {
                    {"username", logOnModel.UserName},
                    {"password", logOnModel.Password}
                };

                var rdm = await
                    RequestManager.CreateRequest(postData, RequestURL.LogOn, ApplicationConstants.RequestType.POST);

                if (rdm.IsError) return rdm;

                var rslt = true;
                var userModel = XmlToModelMapper.LogOnModelMapper(rdm.Data.ToString().Trim());
                //rdm.Data = userModel;

                //TODO : Write database calls here for response data
                //Update user database records

                #region Suren - Commented

                /*if (await _dbOperation.UserDatabaseIsExist(userModel.UserId.ToString()))
                    {
                        userModel.Password = CryptoService.HashPassword(logOnModel.Password);
                        rslt = await _authDAO.UpdateUserAsync(userModel);

                        UserModel um = (UserModel)rdm.Data;
                        //TODO: check User table's timestamps if null its a first time else its not the first time
                        um.IsFirstTimeCheck = false;
                        rdm.Data = um;
                    }
                    else
                    {
                        bool dbCreationRslt = await _dbOperation.CreateUserDatabase(userModel.UserId);

                        if (dbCreationRslt)
                        {
                            UserModel um = (UserModel)rdm.Data;
                            um.IsFirstTimeCheck = true;
                            rdm.Data = um;

                            userModel.Password = CryptoService.HashPassword(logOnModel.Password);
                            rslt = await _authDAO.InsertUserAsync(userModel); 
                        }
                    }*/

                #endregion

                #region New Code For above commented code

                userModel.IsFirstTimeCheck = false;
                if (!await _dbOperation.IsUserDatabaseExists(userModel.UserId.ToString())) //Not exist
                {
                    userModel.IsFirstTimeCheck = true;
                    var dbCreationRslt = await _dbOperation.CreateUserDatabase(userModel.UserId);
                }


                Random random = new Random();
                uint saltSize = (uint)random.Next(10, 15);
                IBuffer randomBuffer = CryptographicBuffer.GenerateRandom(saltSize);
                string randomString = CryptographicBuffer.EncodeToBase64String(randomBuffer);
                userModel.Password = CryptoService.HashPasswordB(randomString, logOnModel.Password);
                userModel.PasswordSalt = randomString;
                var rdModel = await _authDAO.InsertOrUpdateUserAsync(userModel);
                if (rdModel.IsError) rslt = false;
                if (!rdModel.IsError)
                {
                    userModel.IsFirstTimeCheck = (bool) rdModel.Data;
                }
                rdm.Data = userModel;

                #endregion

                //Check user database updated successfully
                if (!rslt)
                {
                    rdm.IsError = true;
                    rdm.ErrorMessage = "Cannot update user details";
                    return rdm;
                }

                //Update general database records                    
                rslt = await _authDAO.InsertOrUpdateUserMapperAsync(userModel);

                //Check general database updated successfully
                if (rslt) return rdm;

                rdm.IsError = true;
                rdm.ErrorMessage = "Cannot update user mapper details";
                return rdm;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> LogOnOffline(LogOnModel logOnModel)
        {
            try
            {
                return await _authDAO.LogOnOffline(logOnModel);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<DeviceModel> GetDeviceAuthStatus()
        {
            try
            {
                return await _authDAO.GetDeviceAuthStatus();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> SetDeviceAuthStatus(DeviceModel deviceModel)
        {
            try
            {
                return await _authDAO.SetDeviceAuthStatus(deviceModel);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<DeviceModel> AuthorizeDevice(LogOnModel logOnModel)
        {
            var deviceModel = new DeviceModel();
            try
            {
                var postData = new Dictionary<string, string>
                {
                    {"UserName", logOnModel.UserName.Trim()},
                    {"Password", logOnModel.Password}
                };
                if (logOnModel.MemberUserName != null)
                    postData.Add("adminName", logOnModel.MemberUserName.Trim());
                postData.Add("deviceId", logOnModel.DeviceId.Trim());

                var responseModel =
                    await
                        RequestManager.CreateRequest(postData, RequestURL.AuthorizeDevice,
                            ApplicationConstants.RequestType.POST);
                deviceModel.IsError = responseModel.IsError;

                if (responseModel.IsError)
                {
                    deviceModel.ErrorMessage = responseModel.ErrorMessage;
                    return deviceModel;
                }

                deviceModel.DeviceRegistrationStatus = (int) DeviceStatus.Pending;
                await _authDAO.SetDeviceAuthStatus(deviceModel);
                return deviceModel;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /*public async Task<DeviceModel> DeviceAuthorizeStatus(LogOnModel logOnModel)
        {
            DeviceModel deviceModel = new DeviceModel();
            try
            {
                Dictionary<string, string> postData = new Dictionary<string, string>();
                postData.Add("deviceId", logOnModel.DeviceId.Trim());

                var rslt = await RequestManager.CreateRequest(postData, RequestURL.DeviceStatusCheck, RequestType.POST);
                ResponseDataModel responseModel = XmlParser.Parse(rslt.ToString());
                deviceModel.IsError = responseModel.IsError;

                if (responseModel.IsError)
                {
                    deviceModel.ErrorMessage = responseModel.ErrorMessage;
                    return deviceModel;
                }

                //deviceModel.DeviceRegStatus = (int)DeviceRegStatus.Pending;
                //await _authDAO.SetDeviceAuthStatus(deviceModel);

                //deviceModel.DeviceStatus = XmlParser.GetDeviceAuthorizationStatus(rslt.ToString());

                //responseModel.Data

                return deviceModel;
            }
            catch (Exception)
            {
                throw;
            }
        }*/

        public async Task<ResponseDataModel> DeviceAuthorizeStatus(string deviceId)
        {
            var rdm = new ResponseDataModel();
            try
            {
                var postData = new Dictionary<string, string> {{"deviceId", deviceId}};

                rdm =
                    await
                        RequestManager.CreateRequest(postData, RequestURL.DeviceStatusCheck,
                            ApplicationConstants.RequestType.POST);

                if (rdm.IsError)
                    return rdm;

                rdm.Data = XmlToModelMapper.GetDeviceAuthorizeStatus(rdm.Data.ToString());
            }
            catch (Exception)
            {
                rdm.IsError = true;
                rdm.ErrorMessage = "Service error";
            }
            return rdm;
        }

        public async Task<AppSettingModel> GetSupportInfoFromDb()
        {
            try
            {
                return await _authDAO.GetSupportInfoFromDb();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<object> GetSettingValueBySettingName(DatabaseType dbtype, string settingName)
        {
            try
            {
                return await _authDAO.GetSettingValueBySettingName(dbtype, settingName);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<object> GetSettingUsageValueBySettingName(string settingName)
        {
            try
            {
                return await _authDAO.GetSettingUsageValueBySettingName(settingName);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<bool> SetSettingUsageValueBySettingName(string settingName, string value)
        {
            try
            {
                return await _authDAO.SetSettingUsageValueBySettingName(settingName, value);
            }
            catch (Exception)
            {
                return false;
            }
        }

        public async Task<ResponseDataModel> ChangePassword(LogOnModel logOnModel)
        {
            var rdm = new ResponseDataModel();
            try
            {
                var postData = new Dictionary<string, string>
                {
                    {"OldPassword", logOnModel.OldPassword},
                    {"NewPassword", logOnModel.NewPassword},
                    {"ConfirmPassword", logOnModel.ConfirmNewPassword}
                };

                rdm =
                    await
                        RequestManager.CreateRequest(postData, RequestURL.ChangePassword,
                            ApplicationConstants.RequestType.POST);

                //NOTE: err_106 means success. This is a backend bullshit!!!
                if (rdm.IsError && rdm.ErrorCode.Equals("err_106"))
                {
                    rdm.IsError = false;
                    return rdm;
                }

                if (rdm.IsError) return rdm;
            }
            catch (Exception)
            {
                rdm.IsError = true;
                rdm.ErrorMessage = "Service error";
            }
            return rdm;
        }

        public async Task Logout()
        {
            try
            {
                await RequestManager.CreateRequest(null, RequestURL.Logout, ApplicationConstants.RequestType.GET);
            }
            catch (Exception)
            {
            }
        }

        public async Task<ResponseDataModel> WipeoutDevice()
        {
            try
            {
                return await _authDAO.WipeoutDevice();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> ResetDevice()
        {
            try
            {
                return await _authDAO.ResetDevice();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> CleanDecryptedAgendaItems()
        {
            try
            {
                return await _authDAO.CleanDecryptedAgendaItems();
            }
            catch (Exception)
            {
                return false;
            }
        }

        public async Task<UserModel> GetUserFromId()
        {
            try
            {
                return await _authDAO.GetUserFromId(Global.UserId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool CloseAllConnections()
        {
            try
            {
                return _dbOperation.CloseAllConnections();
            }
            catch (Exception)
            {
                return false;
            }
        }

        public async Task<AppSettingModel> GetAppVersions()
        {
            try
            {
                var asm = new AppSettingModel();
                var webV =
                    await
                        GetSettingValueBySettingName(DatabaseType.GeneralDb,
                            ApplicationConstants.GeneralDbSettingNames.WebAppVersion);
                asm.CurrentWebVersion = webV.ToString();

                var webMinV =
                    await
                        GetSettingValueBySettingName(DatabaseType.GeneralDb,
                            ApplicationConstants.GeneralDbSettingNames.MinWebVersion);
                asm.MinWebVersion = webMinV.ToString();
                return asm;
            }
            catch (Exception)
            {
                return null;
            }
        }


        public async Task<string> CheckAndInitiateDateFormat()
        {
            try
            {
                return await _authDAO.CheckAndInitiateDateFormat();
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}